package com.xpec.c4.service.module.gateway;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.game.common.message.ServerMaintainAction;
import com.ms.game.common.message.ServerReadyAction;
import com.ms.game.gmtool.message.SGmtoolKickAllConnectionNotify;
import com.ms.service.module.daemon.message.SSetGatewayStat;
import com.ms.service.module.daemon.message.SSetGatewayStatResult;
import com.ms.service.telnet.STelnetCmd;
import com.ms.service.telnet.TelGUID;
import com.xpec.c4.game.system.InitData;
import com.xpec.c4.game.time.TimeConstants;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.net.XSENetSession;
import com.xpec.c4.service.exceptions.GroupTransportException;
import com.xpec.c4.service.group.ServerGroup;
import com.xpec.c4.service.group.transportlayer.GroupMessage;
import com.xpec.c4.service.message.MessageAction;
import com.xpec.c4.service.module.BasicServiceModule;
import com.xpec.c4.service.module.ModuleName;
import com.xpec.c4.service.module.ServerProperties;
import com.xpec.c4.service.module.task.TaskTimer;
import com.xpec.c4.service.server.CloseType;
import com.xpec.c4.service.server.Server;

/**
 * 
 * 
 * @author lipeilin
 * @2011-3-9 下午05:00:32
 *
 */
public class GatewayModule extends BasicServiceModule //implements Runnable
{
	private static final Log log = LogFactory.getLog(GatewayModule.class);
	
	/**
	 * 连接的Session列表<br>
	 * key为session address<br>
	 * value为session实体
	 */
	private Map<GUID, XSENetSession> sessions = Collections.synchronizedMap(new HashMap<GUID, XSENetSession>());

	/**
	 * 登入狀態
	 */
	private Map<GUID, SessionStatus> sessions2  = new ConcurrentHashMap<GUID, SessionStatus>();
	
	/**
	 * 不同平台的連線數
	 */
	private Map<Integer, Integer> connectionCount = Collections.synchronizedMap(new HashMap<Integer, Integer>());

	/**
	 * 
	 */
	private GatewayService service ;
	
	/**
	 *  多張網卡要bind的ip
	 */
	protected String bindIp;
	
	/**
	 *  丟給client連線用的ip
	 */
	protected String ip;
	
	/**
	 *  丟給client連線用的port
	 */
	protected int port;
	
	/**
	 * 實際要聽的port
	 */
	protected int listenPort;
	
	/**
	 * 
	 */
	protected int maxcount;
	
	private Object waitObject = new Object();
	
	private boolean moduleStart = false;
	
	public GatewayModule()
	{
		super();
	}
	

	public Map<String,Integer> getStatistics()
	{
		Map<String,Integer> map = super.getStatistics();
		
		map.put("connections",service.getAcceptedCount());
		map.put("nettyBpsInput",service.getInputBps());
		map.put("nettyBpsOut",service.getOutputBps());
		map.put("nettyPpsInput",service.getInputPps());
		map.put("nettyPpsOut",service.getOutputPps());
		
		return map;
	}	

	/* (non-Javadoc)
	 * @see com.xpec.c4.service.module.IServiceModule#init()
	 */
	@Override
	public void init() {
		super.init();
		
		InitData.initAll();
		
		registerActionClass(GatewayAction.class);
		registerActionClass(ServerReadyAction.class);
		registerActionClass(ServerMaintainAction.class);
		
		bindIp = ServerProperties.getString(getModuleName() + "bindip", null);
		ip = ServerProperties.getString(getModuleName() + "ip", "127.0.0.1");
		port = ServerProperties.getInt(getModuleName() + "port");
		maxcount = ServerProperties.getInt(getModuleName() + "max", 2000);		
		listenPort = ServerProperties.getInt(getModuleName() + "listenPort", port);
		
		if(bindIp != null){
			service = new GatewayService(this, bindIp, listenPort, getModuleName());
		}else{
			service = new GatewayService(this, listenPort, getModuleName());
		}
		
	}

	/* (non-Javadoc)
	 * @see com.xpec.c4.service.module.IServiceModule#start()
	 */
	@Override
	public boolean startup() {

		try {
			registerJmxInfo();

			service.start();

			boolean result = super.startup();

			// 加计时, 处理定时要做的事
			ConnectionCountNotifyTaskTimer tt = new ConnectionCountNotifyTaskTimer(this, service);
			tt.setTimerOption(TaskTimer.LOOP);
			tt.setInitialDelay(10 * TimeConstants.MILLI_SECOND_PRE_SECOND);
			tt.setPeriod(30 * TimeConstants.MILLI_SECOND_PRE_SECOND);
			addTaskTimer(tt);

			return result;			
			
		} catch (IOException e) {
			log.error("GatewayModule start error ",e);
			return false;
		}
		
	}
	
	/**
	 * 
	 * @param obj
	 */
	public void setServiceStat(boolean stat){
		if(service != null){
			try{
				service.enableService(stat);
			}catch(Exception e){
				log.error("GatewayService set Stat error ",e);
			}
		}
	}

	/**
	 * 
	 * @param obj
	 */
	public void kickConnection(CloseType closeType){
		if(service != null){
			service.kickAllConnect(closeType, this);
		}
	}

	/* (non-Javadoc)
	 * @see com.xpec.c4.service.module.IServiceModule#stop()
	 */
	@Override
	public void shutdown() {
		
		service.stop();
		
		super.shutdown();
	}
	
	/**
	 * 
	 */
	public void addSession(GUID key, XSENetSession session)	{
		sessions.put(key, session);
		
		SessionStatus data = new SessionStatus();
		data.session = session;
		data.canSend = false;
		sessions2.put(key, data);
		// sessionsAddress.put(session, key);		
		// log.info(getModuleName() + " !!!!!!!!!!!! Add:" + key);
	}
	
	/**
	 * 
	 */
	public void removeSession(GUID key)
	{
		if(key != null){
			sessions.remove(key);
			SessionStatus removeObj = sessions2.remove(key);
			
		}
		
		// XSENetSession value = sessions.get(key);
		// if(value != null){
			// sessions.remove(key);
			// sessionsAddress.remove(value);
			// log.info(getModuleName() + " !!!!!!!!!!!! Remove:" + key);
		// }
	}
	
	/**
	 * 
	 * @param guid
	 * @param status
	 */
	public void setSessionStatus(GUID guid, int status){
		SessionStatus value = sessions2.get(guid);
		if(value != null){
			value.canSend = (status!=0) ? true : false;
			
			//現在無其他平台
			Integer connValue = connectionCount.get(0);
			if (connValue != null) {
				connectionCount.put(0,
						new Integer(connValue.intValue() + 1));
			} else {
				// 增加, 並且有一條連線
				connectionCount.put(0, new Integer(1));
			}
		}
	}
	
	/**
	 * 
	 * @return
	 */
	public Collection<XSENetSession> getAllSession(){
		return sessions.values();
	}
	
	/**
	 * 用sessionid 檢查 是否是此 gateway 下的連線
	 */
	public boolean checkSessionId(GUID sessionId){
		return sessions.containsKey(sessionId);
	}

	/**
	 * 
	 * @return
	 */
	public Collection<SessionStatus> getAllSession2(){
		return sessions2.values();
	}
	
	/**
	 * 
	 */
	public void notifyAccount()
	{
		threadNotify();
		
		synchronized(waitObject)
		{
			waitObject.notify();
		}
	}

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public int getMaxcount() {
		return maxcount;
	}

	public void setMaxcount(int maxcount) {
		this.maxcount = maxcount;
	}


	@Override
	public void onModuleServerReadyStart() {
		super.onModuleServerReadyStart();
		moduleStart = true;
	}


	public boolean isModuleStart() {
		return moduleStart;
	}


	public void setModuleStart(boolean moduleStart) {
		this.moduleStart = moduleStart;
	}
	
	public void registerJmxInfo()
	{
		MBeanServer  mbserver = ManagementFactory.getPlatformMBeanServer();
		GatewayStat bean = new GatewayStat();
		 
		try 
		{
			ObjectName name = new ObjectName("Gateway:name=" + this.toString());
			mbserver.registerMBean(bean, name);
		} 
		catch (Exception e)
		{
			log.error(e, e);
		}
	}
	
	/**
	 * 返回當前狀態
	 */
	private void feedbackStatus(TelGUID guid) {

		boolean stat = service.isNewConnectionAllowed();
		String result = "IP: " + ip
				+ ((bindIp != null) ? "(" + bindIp + ")" : "") + "\r\nPort: "
				+ service.getPort() + "\r\nStatus: "
				+ ((stat) ? "Services" : "Stop Service") + "\r\nMax Count: "
				+ maxcount + "\r\nTotal Connect:"
				+ service.getHistoryConnectCount() + "\r\nCurrect Connect:"
				+ service.getAcceptedCount();
		telnetString(guid, result);
	}
	
//	private void feedbackTelnetMessage(TelGUID guid, String msg) {
//
//		boolean stat = service.isNewConnectionAllowed();
//		String result = "IP: " + ip
//				+ ((bindIp != null) ? "(" + bindIp + ")" : "") + "\r\nPort: "
//				+ service.getPort() + "\r\nStatus: "
//				+ ((stat) ? "Services" : "Stop Service") + "\r\nMax Count: "
//				+ maxcount + "\r\nConnect Count:" + service.getAcceptedCount();
//		telnetString(guid, msg);
//	}
//	
	
	/**
	 * 
	 */
	public void procTelnetCommand(STelnetCmd obj){
		
		if(obj.command == null){
			// 沒參數就顯示狀態			
			feedbackStatus(obj.guid);
			return;
		}
		String cmd [] = obj.command.split(" ");
		
		if(cmd.length < 1){
			// 沒參數就顯示狀態
			feedbackStatus(obj.guid);
			return;
		}
		
		// 兩個以上
		if (cmd.length > 1) {
			
			if (cmd[0].equals(this.getModuleName())) {
				try {
					int val = Integer.parseInt(cmd[1]);
					if(val >= 0){
						maxcount = val;
						telnetString(obj.guid, "MaxCount change to: " + maxcount + "\r\n");
						return;
					}					
				} catch (NumberFormatException e) {

				}
			}
			
			return;

		} else {

			if (cmd[0].equals("on")) {
				setServiceStat(true);
			} else if (cmd[0].equals("off")) {
				setServiceStat(false);
			} else if (cmd[0].equals("kick")) {
				kickConnection(CloseType.KICK_BY_GM);
			}
		}
		
		feedbackStatus(obj.guid);
	}


	public Map<Integer, Integer> getConnectionCount() {
		return connectionCount;
	}


	public void setConnectionCount(Map<Integer, Integer> connectionCount) {
		this.connectionCount = connectionCount;
	}
	
	/**
	 * 目前用在關服
	 * @param obj
	 */
	public void setGatewayStatus(SSetGatewayStat obj){

		if(obj.serviceStat){
			setServiceStat(true);
		}else{
			setServiceStat(false);
		}
		
		if(obj.kick){
			kickConnection(CloseType.KICK_BY_GM);
		}
		
		service.stop();
		
		SSetGatewayStatResult info = new SSetGatewayStatResult();
		info.telGuid = obj.telGuid;
		info.moduleId = this.getModuleName();
	
		GroupMessage msg = new GroupMessage();
		msg.setMessageType(MessageTypes.S_DAEMON_SET_GATEWAY_STAT_RESULT);
		msg.setMessageContent(info);
		
		msg.setDestModuleID(ModuleName.DAEMON);
		MessageAction.sendGroupMessage(msg);
	}


	@Override
	public void procThrowException(Object obj) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onRecvKickAllConnectionNotify(SGmtoolKickAllConnectionNotify request) {
		super.onRecvKickAllConnectionNotify(request);

		// 通知 client 被斷線
		for (Map.Entry<GUID, SessionStatus> entry : sessions2.entrySet()) {
			GUID sessionId = entry.getKey();

			MessageAction.sendMessage(sessionId, MessageTypes.S_ACCOUNT_CHARACTER_KICK_BY_SERVER,
					CloseType.KICK_BY_SERVER_SHUTDOWN);

			// 等待一下讓消息送出
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		// 斷線
		kickConnection(CloseType.KICK_BY_SERVER_SHUTDOWN);
	}


	public Map<GUID, SessionStatus> getSessions2() {
		return sessions2;
	}
}




/**
 * 连线数计时器
 * @author yangbingyan
 *
 */
class ConnectionCountNotifyTaskTimer extends TaskTimer{

	private static final Log log = LogFactory.getLog(ConnectionCountNotifyTaskTimer.class);
	/**
	 * 
	 */
	private GatewayModule module ;
	
	/**
	 * 
	 */
	private Server service;	

	/**
	 * 
	 */
	private String text;
	
	/**
	 * 
	 * @param module
	 * @param service
	 * @param maxCount
	 */
	public ConnectionCountNotifyTaskTimer(GatewayModule module, Server service){
		this.module = module;
		this.service = service;
	}
	
	public void setText(String text) {
		this.text = text;
	}

	public String getText() {
		return text;
	}
	
	/**
	 * 
	 */
//	@SuppressWarnings("unused")
//	private void again(){
//		
//		ConnectionCountNotifyTaskTimer tt = new ConnectionCountNotifyTaskTimer(module, service);
//		tt.setTimerOption(TaskTimer.ONCE);
//		tt.setInitialDelay(10* 1000);
//		// tt.setPeriod(3 * 1000);
//		module.addTaskTimer(tt);
//	}

	@Override
	public void execute() {
		//自己還沒開完 or 還沒收到account 掠過
		if( !this.module.isModuleStart() ){
			return;
		}

		///////////////////////////////////////
		// 取得所有連線數 (在線人數)
		int totalCnt = service.getAcceptedCount();
		
		// 取得線上所有機器人數量
		int robotCnt = 0;
		if(service instanceof GatewayService){
			GatewayService gs = (GatewayService) service;
			robotCnt = gs.getRobotCount();
		}

		try {
			CGatewayLoadingInfo msg = new CGatewayLoadingInfo();
			msg.name = module.getModuleName();
			msg.gatewayIP = module.getIp();
			msg.gatewayPort = "" + module.getPort();
			msg.playerConnectCount = totalCnt - robotCnt;
			msg.robotConnectCount = robotCnt;
			
			GroupMessage gm = new GroupMessage();
			gm.setDestModuleID(ModuleName.ACCOUNT);
			gm.setMessageType(MessageTypes.S_ACCOUNT_GATEWAY_LOADINGINFO);
			gm.setMessageContent(msg);
	
			ServerGroup.getTransportManager().sendMessage(gm);
			
			// again();
		}
		catch(GroupTransportException ex){
			
		}
		catch(Exception ex){			
		}		
	}	
}

